package br.com.obardavez.util;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

import br.com.obardavez.util.impl.BeanUtilImpl;

import com.google.inject.ImplementedBy;

@ImplementedBy(BeanUtilImpl.class)
public interface BeanUtil extends Serializable {
	
	/**
	 * 
	 * @param beanClass
	 * @param superType
	 * @return
	 */
	Boolean instanceOf(Class<?> beanClass, Class<?> superType);

	/**
	 * Recupera a classe do primeiro atributo generico para o objeto informado
	 * 
	 * @param obj
	 *            Objeto que possui o atributo generico
	 * @return Classe do atributo generico
	 */
	Class<?> getGenericAttr(Object obj);

	/**
	 * Recupera a classe do primeiro atributo generico para a classe informada
	 * 
	 * @param obj
	 *            Objeto que possui o atributo generico
	 * @return Classe do atributo generico
	 */
	Class<?> getGenericAttr(Class<?> objClass);

	/**
	 * Recupera a classe do atributo generico para o objeto informado
	 * 
	 * @param obj
	 *            Objeto que possui o atributo generico
	 * @param indice
	 *            Indice do atributo generico
	 * @return Classe do atributo generico
	 */
	Class<?> getGenericAttr(Object obj, Integer indice);

	/**
	 * Recupera a classe do atributo generico para a classe informada
	 * 
	 * @param objClass
	 *            Classe que possui o atributo generico
	 * @param indice
	 *            Indice do atributo generico
	 * @return Classe do atributo generico
	 */
	Class<?> getGenericAttr(Class<?> objClass, Integer indice);

	/**
	 * Retrieve property name through the name of the method
	 * 
	 * @param methodName
	 * @return property name
	 */
	String getPropertyFromGetter(String methodName);

	/**
	 * Retrieve property name through the name of the method
	 * 
	 * @param methodName
	 * @return property name
	 */
	String getPropertyFromSetter(String methodName);

	/**
	 * Verifica se o metodo informado representa um metodo getter
	 * 
	 * @param method
	 *            Metodo que esta sendo verificado
	 * @return Boolean que indica se o metodo informado representa um getter de
	 *         uma propriedade
	 */
	Boolean isGetter(Method method);

	/**
	 * Verifica se o metodo informado representa um metodo setter
	 * 
	 * @param method
	 *            Metodo que esta sendo verificado
	 * @return Boolean que indica se o metodo informado representa um setter de
	 *         uma propriedade
	 */
	Boolean isSetter(Method method);

	/**
	 * Recupera o metodo setter para a propriedade informada
	 * 
	 * @param clazz
	 *            Classe do objeto
	 * @param propertyName
	 *            Propriedade para a qual sera recuperado o metodo setter
	 * @return Metodo setter da propriedade
	 */
	Method getSetterMethodFromProperty(Class<?> clazz, String propertyName);
	
	
	/**
	 * Recupera o metodo getter para a propriedade informada
	 * 
	 * @param clazz
	 *            Classe do objeto
	 * @param propertyName
	 *            Propriedade para a qual sera recuperado o metodo getter
	 * @return Metodo getter da propriedade
	 */
	Method getGetterMethodFromProperty(Class<?> clazz, String propertyName);
	
	/**
	 * Recupera o nome da propridade cujo metodo getter esta marcado com a
	 * anotacao informada
	 * 
	 * @param obj
	 *            Objeto que armazena a propriedade
	 * @param annotationClass
	 *            Anotacao que marca o metodo getter
	 * @return Nome da propriedade
	 */
	String getPropertyName(Class<?> entityClass,Class<? extends Annotation> annotationClass);
	
	/**
	 * Recupera o nome da propridade que representa a coluna informada
	 * 
	 * @param entityClass
	 *            Classe a partir da qual será recuperada a propriedade
	 * @param columnName
	 *            Nome da coluna
	 * @return Nome da propriedade
	 */
	String getPropertyName(Class<?> entityClass, String columnName);
	
	/**
	 * Recupera a lista com o nome dos atributos que não estão vazios.
	 * @param instance
	 * @return
	 */
	List<String> getNotEmptyPropertyNames(Object instance);
	
	 String getColumnName(Object obj,
				Class<? extends Annotation> annotationClass);
	 
	 String getColumnName(Class<?> objClass,
				Class<? extends Annotation> annotationClass);
	
	String getColumnName(Class<?> objClass, String fieldName);
	
	
	/**
	 * Recupera o valor da propridade cujo metodo getter esta marcado com a
	 * anotacao informada
	 * 
	 * @param obj
	 *            Objeto que armazena a propriedade
	 * @param annotationClass
	 *            Anotacao que marca o metodo getter
	 * @return Valor da propriedade
	 */
	Object getPropertyValue(Object obj,
			Class<? extends Annotation> annotationClass);
	
	/**
	 * Recupera o valor da propridade com o nome informado
	 * 
	 * @param obj
	 *            Objeto que armazena a propriedade
	 * @param propertyName
	 *            Nome da propriedade
	 * @return Valor da propriedade
	 */
	Object getPropertyValue(Object obj, String propertyName);
	
	/**
	 * Recupera os valores da propridade cujo metodo getter esta marcado com a
	 * anotacao informada
	 * 
	 * @param objs
	 *            List de objetos que armazenam a propriedade
	 * @param annotationClass
	 *            Anotacao que marca o metodo getter
	 * @return Valores da propriedade
	 */
	<T> List<T> getPropertyValues(List<? extends Object> objs,
			Class<? extends Annotation> annotationClass, Class<T> returnType) ;
	
	/**
	 * 
	 * @param obj
	 * @param propertyName
	 * @param value
	 */
	void setPropertyValue(Object obj, String propertyName, Object value);
	
	/**
	 * 
	 * @param entityClass
	 * @param items
	 * @return
	 */
	<E> List<E> generateList(Class<E> entityClass,
			List<Map<String, Object>> items);


	/**
	 * 
	 * @param obj
	 * @param annotationClass
	 * @return
	 */
	<T  extends Annotation> T getAnnotationInType(Object obj,
			Class<T> annotationClass);
	

}